package com.sunhao.springboot_satoken.controller;

import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpUtil;
import com.sunhao.springboot_satoken.domain.dos.RoleDo;
import com.sunhao.springboot_satoken.domain.dos.UserDo;
import com.sunhao.springboot_satoken.domain.req.LoginReq;
import com.sunhao.springboot_satoken.domain.req.RegisterReq;
import com.sunhao.springboot_satoken.service.CaptchaService;
import com.sunhao.springboot_satoken.service.RoleService;
import com.sunhao.springboot_satoken.service.UserService;
import com.sunhao.springboot_satoken.utils.Response;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.DigestUtils;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * 认证控制器
 * 提供登录、注册、退出登录等功能
 * 
 * @author SunHao
 */
@RestController
@RequestMapping("/auth")
@Slf4j
@Validated
@RequiredArgsConstructor
public class AuthController {

    private final CaptchaService captchaService;
    private final UserService userService;
    private final RoleService roleService;
    
    // 响应码常量
    private static final String SUCCESS_CODE = "200";
    private static final String SUCCESS_LOGIN_MSG = "登录成功";
    private static final String SUCCESS_REGISTER_MSG = "注册成功";
    private static final String SUCCESS_LOGOUT_MSG = "退出成功";
    
    private static final String ERROR_PARAM_CODE = "100001";
    private static final String ERROR_CAPTCHA_CODE = "100002";
    private static final String ERROR_USERNAME_CODE = "100003";
    private static final String ERROR_PASSWORD_CODE = "100004";
    private static final String ERROR_REGISTER_CODE = "100005";
    private static final String ERROR_LOGOUT_CODE = "100006";
    
    private static final String ERROR_PARAM_MSG = "参数不完整，请检查输入";
    private static final String ERROR_CAPTCHA_MSG = "验证码错误或已过期";
    private static final String ERROR_USERNAME_MSG = "用户名不存在";
    private static final String ERROR_PASSWORD_MSG = "密码错误";
    private static final String ERROR_REGISTER_MSG = "注册失败，请检查输入或稍后重试";
    private static final String ERROR_LOGOUT_MSG = "退出失败，请稍后重试";

    /**
     * 用户登录
     * 
     * @param loginRequest 登录请求参数
     * @return 登录结果
     */
    @PostMapping("/login")
    public Response<Map<String, Object>> login(@RequestBody @Validated LoginReq loginRequest) {
        log.info("用户登录请求: {}", loginRequest.getUsername());
        
        // 1. 校验参数完整性
        if (!isLoginRequestValid(loginRequest)) {
            log.warn("登录参数不完整: {}", loginRequest);
            return new Response<>(ERROR_PARAM_CODE, ERROR_PARAM_MSG, null);
        }

        // 2. 验证验证码
        if (!captchaService.validateCaptcha(loginRequest.getCaptchaKey(), loginRequest.getCaptcha())) {
            log.warn("验证码错误: key={}, captcha={}", loginRequest.getCaptchaKey(), loginRequest.getCaptcha());
            return new Response<>(ERROR_CAPTCHA_CODE, ERROR_CAPTCHA_MSG, null);
        }

        // 3. 根据用户名查询用户
        UserDo user = userService.selectUserByName(loginRequest.getUsername());
        if (user == null) {
            log.warn("用户名不存在: {}", loginRequest.getUsername());
            return new Response<>(ERROR_USERNAME_CODE, ERROR_USERNAME_MSG, null);
        }

        // 4. 验证密码
//        String encryptedPassword = DigestUtils.md5DigestAsHex(loginRequest.getPassword().getBytes());
        if (!loginRequest.getPassword().equals(user.getPassword())) {
            log.warn("密码错误: username={}", loginRequest.getUsername());
            return new Response<>(ERROR_PASSWORD_CODE, ERROR_PASSWORD_MSG, null);
        }

        // 5. 登录成功，生成Token
        StpUtil.login(user.getId());
        SaTokenInfo tokenInfo = StpUtil.getTokenInfo();
        log.info("用户登录成功: userId={}", user.getId());

        // 6. 获取用户角色信息
        RoleDo role = roleService.selectRoleById(user.getRoleId());

        // 7. 组装返回数据
        Map<String, Object> data = new HashMap<>(5);
        data.put("token", tokenInfo.getTokenValue());
        data.put("userId", user.getId());
        data.put("username", user.getUsername());
        data.put("nickname", user.getNickname());
        data.put("role", role);

        return new Response<>(SUCCESS_CODE, SUCCESS_LOGIN_MSG, data);
    }
    
    /**
     * 用户注册
     * 
     * @param registerReq 注册请求参数
     * @return 注册结果
     */
    @PostMapping("/register")
    public Response<Map<String, Object>> register(@RequestBody @Validated RegisterReq registerReq) {
        log.info("用户注册请求: {}", registerReq.getUsername());
        
        // 1. 校验参数完整性
        if (!isRegisterRequestValid(registerReq)) {
            log.warn("注册参数不完整: {}", registerReq);
            return new Response<>(ERROR_PARAM_CODE, ERROR_PARAM_MSG, null);
        }
        
        // 2. 验证验证码
        if (!captchaService.validateCaptcha(registerReq.getCaptchaKey(), registerReq.getCaptcha())) {
            log.warn("验证码错误: key={}, captcha={}", registerReq.getCaptchaKey(), registerReq.getCaptcha());
            return new Response<>(ERROR_CAPTCHA_CODE, ERROR_CAPTCHA_MSG, null);
        }
        
        // 3. 验证密码一致性
        if (!Objects.equals(registerReq.getPassword(), registerReq.getConfirmPassword())) {
            log.warn("密码与确认密码不一致: username={}", registerReq.getUsername());
            return new Response<>(ERROR_REGISTER_CODE, "密码与确认密码不一致", null);
        }
        
        // 4. 调用注册服务
        UserDo userDo = userService.register(registerReq);
        if (userDo == null) {
            log.error("用户注册失败: {}", registerReq.getUsername());
            return new Response<>(ERROR_REGISTER_CODE, ERROR_REGISTER_MSG, null);
        }
        
        log.info("用户注册成功: userId={}", userDo.getId());
        
        // 5. 注册成功，返回用户信息（不包含敏感信息）
        Map<String, Object> data = new HashMap<>(3);
        data.put("userId", userDo.getId());
        data.put("username", userDo.getUsername());
        data.put("nickname", userDo.getNickname());
        
        return new Response<>(SUCCESS_CODE, SUCCESS_REGISTER_MSG, data);
    }
    
    /**
     * 退出登录
     * 
     * @return 退出结果
     */
    @SaCheckLogin
    @PostMapping("/logout")
    public Response<Void> logout() {
        try {
            // 获取当前登录用户ID
            Object loginId = StpUtil.getLoginId();
            log.info("用户退出登录: userId={}", loginId);
            
            // 退出登录
            StpUtil.logout();
            return new Response<>(SUCCESS_CODE, SUCCESS_LOGOUT_MSG, null);
        } catch (Exception e) {
            log.error("退出登录异常", e);
            return new Response<>(ERROR_LOGOUT_CODE, ERROR_LOGOUT_MSG, null);
        }
    }
    
    /**
     * 校验登录请求参数是否有效
     * 
     * @param loginReq 登录请求
     * @return 是否有效
     */
    private boolean isLoginRequestValid(LoginReq loginReq) {
        return StringUtils.hasText(loginReq.getUsername()) &&
               StringUtils.hasText(loginReq.getPassword()) &&
               StringUtils.hasText(loginReq.getCaptcha()) &&
               StringUtils.hasText(loginReq.getCaptchaKey());
    }
    
    /**
     * 校验注册请求参数是否有效
     * 
     * @param registerReq 注册请求
     * @return 是否有效
     */
    private boolean isRegisterRequestValid(RegisterReq registerReq) {
        return StringUtils.hasText(registerReq.getUsername()) &&
               StringUtils.hasText(registerReq.getPassword()) &&
               StringUtils.hasText(registerReq.getConfirmPassword()) &&
               StringUtils.hasText(registerReq.getCaptcha()) &&
               StringUtils.hasText(registerReq.getCaptchaKey());
    }
}
